package com.binarysoft.service.common.job;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.binarysoft.service.common.quartz.QuartzService;
import common.framework.dsb.AbstractServiceBean;
import common.framework.dsb.annotation.DSBService;
import common.framework.dsb.service.ServiceContext;

@DSBService(name = "DSB/JobService", startup = true)
public class JobServiceBean extends AbstractServiceBean implements JobService {

	Collection<JobConfig> jobConfigs = new ArrayList<JobConfig>();

	@Override
	public void start(ServiceContext serviceContext) throws Exception {
		super.start(serviceContext);
		serviceContext.loadConfigProperties("job.properties");
		String thread_pool_count = serviceContext.getProperty("thread_pool_count");
		System.setProperty("org.quartz.threadPool.threadCount", thread_pool_count);

		jobConfigs.addAll(loadJobs("job-config.xml"));

		QuartzService quartzService = serviceContext.lookup("DSB/QuartzService");

		for (JobConfig jobConfig : jobConfigs) {
			// job_class 必须实现 org.quartz.Job接口
			Class jobClass = Class.forName(jobConfig.getJob_class());
			Job jobObj = (Job) jobClass.newInstance();

			String jobName = jobConfig.getName();
			String jobGroup = jobConfig.getGroup();
			String cron_exp = jobConfig.getCron_exp();

			JobDetail jobDetail = newJob(jobObj.getClass()).withIdentity(jobName, jobGroup).usingJobData("name", jobName).build();
			String triggerName = "triger-" + jobName;
			CronTrigger cronTrigger = newTrigger().withIdentity(triggerName, jobGroup).withSchedule(cronSchedule(cron_exp)).build();
			quartzService.scheduleJob(jobDetail, cronTrigger);
		}
	}

	@Override
	public Collection<JobConfig> getJobConfigs() throws Exception {
		return jobConfigs;
	}

	@Override
	public boolean fireJob(String jobName) throws Exception {
		boolean result = false;
		for (JobConfig jobConfig : jobConfigs) {
			if (jobConfig.getName().equals(jobName)) {
				Class jobClass = Class.forName(jobConfig.getJob_class());
				Job jobObj = (Job) jobClass.newInstance();
				jobObj.execute(null);
				result = true;
			}
		}
		return result;
	}

	@Override
	public void refresh() throws Exception {
	}

	@Override
	public void close() throws Exception {
		jobConfigs.clear();
	}

	private Collection<JobConfig> loadJobs(String configFile) throws Exception {

		Collection<JobConfig> result = new ArrayList<JobConfig>();
		DocumentBuilderFactory docBuildFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = docBuildFactory.newDocumentBuilder();
		InputStream inputStream = serviceContext.getConfigFile(configFile).openStream();
		Document doc = docBuilder.parse(inputStream);
		Element root = doc.getDocumentElement();
		NodeList jobs = root.getChildNodes();

		for (int i = 0; i < jobs.getLength(); i++) {
			Node jobNode = jobs.item(i);
			if (!jobNode.getNodeName().equalsIgnoreCase("job")) {
				continue;
			}
			String jobName = getAttribute(jobNode, "name");
			String jobGroup = getAttribute(jobNode, "group");
			String cron_exp = getAttribute(jobNode, "cron_exp");
			String job_class = getAttribute(jobNode, "job_class");

			if (isEmpty(jobName) || isEmpty(jobGroup) || isEmpty(cron_exp) || isEmpty(job_class)) {
				continue;
			}

			JobConfig jobConfig = new JobConfig();
			jobConfig.setName(jobName);
			jobConfig.setGroup(jobGroup);
			jobConfig.setCron_exp(cron_exp);
			jobConfig.setJob_class(job_class);

			result.add(jobConfig);
		}// for
		inputStream.close();

		return result;
	}

	private String getAttribute(Node n, String name) {
		NamedNodeMap nnm = n.getAttributes();
		for (int k = 0; k < nnm.getLength(); k++) {
			String nodeName = nnm.item(k).getNodeName();
			String nodeVal = nnm.item(k).getNodeValue();
			if (name.equalsIgnoreCase(nodeName)) {
				return nodeVal;
			}
		}
		return null;
	}

	private boolean isEmpty(String s) {
		return s == null || s.trim().equalsIgnoreCase("");

	}

}
